#include "requestfactory.h"

#include <cassert>

#include "bufferutil.h"
#include "errorrequest.h"

namespace b2gdns {

	namespace /*anonymous*/ {

		Message::Header parse_header(char*& buffer)
		{
			Message::Header h;
			h.id      = read16bits(buffer);
			unsigned short byte3and4 = read16bits(buffer);
			h.qr      = byte3and4 & 0x8000;
			h.opcode  = byte3and4 & 0x7800;
			h.aa      = byte3and4 & 0x0400;
			h.tc      = byte3and4 & 0x0200;
			h.rd      = byte3and4 & 0x0100;
			h.ra      = byte3and4 & 0x0080;
			h.z       = byte3and4 & 0x0070;
			h.rcode   = byte3and4 & 0x000f;
			h.qdCount = read16bits(buffer);
			h.anCount = read16bits(buffer);
			h.nsCount = read16bits(buffer);
			h.arCount = read16bits(buffer);
			return h;
		}

		bool validate_header(Message::Header const& h)
		{
			return (h.qr == 0u) && (h.opcode <= 15u) && (h.rcode <= 15u);
		}

		std::string parse_qname(char*& buffer)
		{
			// Punycode?
			std::string qname;
			unsigned short ql = static_cast<unsigned char>(*buffer++);
			while (ql != 0u)
			{
				for (unsigned short i = 0u; i < ql; i++)
				{
					char c = *buffer++;
					qname.append(1, c);
				}
				ql = static_cast<unsigned char>(*buffer++);
				if (ql != 0u) qname.append(1,'.');
			}
			return qname;
		}

		unsigned short parse_qtype(char*& buffer)
		{
			return read16bits(buffer);
		}

		unsigned short parse_qclass(char*& buffer)
		{
			return read16bits(buffer);
		}

	} // anonymous namespace

	std::unique_ptr<Request> RequestFactory::CreateRequest(
		char* buffer, std::size_t length)
	{
		Message::Header h = parse_header(buffer);
		assert(validate_header(h)); // for now assert

		std::vector<std::string> qnames(h.qdCount);
		for (unsigned short i = 0; i < h.qdCount; ++i)
			qnames[i] = parse_qname(buffer);

		unsigned short qtype = parse_qtype(buffer);
		unsigned short qclass = parse_qclass(buffer);

		// TODO create request based on qtype

		return std::unique_ptr<Request>(new ErrorRequest(
			h, qnames, ErrorRequest::not_implemented));
	}

} // namespace b2gdns
